<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.25" charset="UTF-8">
    <meta http-equiv="Content-Type" content="text/html; charset=GBK" />
    <title>雪花效果</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        #box {
            width: 100vw;
            height: 100vh;
            padding: 3px;
            position: absolute;
            background: #05d3e2;
        }
    </style>
</head>
<body>
<div id="box"></div>

<script th:inline="javascript">
    /*<![CDATA[*/
    (function () {
        var screenWidth = screen.availWidth; // 获取屏幕宽度
        var screenHeight = screen.availHeight; // 获取屏幕高度
        var speed = 1; // 雪花下落的速度

        function Snow(size, downSize) {
            this.box = document.getElementById("box"); // 获取容器元素
            this.size = size; // 雪花数量
            this.downSize = downSize || 10; // 每次落下的雪花数量，默认为10个
            this.item = []; // 雪花元素数组
            this.init(); // 初始化
            this.start(); // 开始下雪
        }

        // 获取相关随机数据的方法
        Snow.prototype.getRandomThings = function (type) {
            var res;
            if (type == 'left') { // 初始的left
                res = Math.round(Math.random() * (screenWidth - 30 - 10)) + 10; // 随机生成left值
                Math.random() > 0.8 ? (res = -res) : null; // 80%的概率使左边的雪花出现在左侧（left为负值）
            } else if (type == 'top') { // 初始的top
                res = -(Math.round(Math.random() * (50 - 40)) + 40); // 随机生成top值，负值使雪花在屏幕上方
            } else if (type == 'incre') { // 向下的速度
                res = Math.random() * (4 - 1) + 1; // 随机生成向下的速度
            } else if (type == 'increLeft') { // 向右的速度
                res = Math.random() * (0.8 - 0.5) + 0.5; // 随机生成向右的速度
            } else { // 雪花的大小
                res = Math.round(Math.random() * (30 - 10)) + 10; // 随机生成雪花的大小
            }
            return res;
        };

        Snow.prototype.init = function () {
            this.box.style.width = screenWidth + 'px'; // 设置容器宽度为屏幕宽度
            this.box.style.height = screenHeight + 'px'; // 设置容器高度为屏幕高度
            var fragment = document.createDocumentFragment(); // 创建文档片段，用于性能优化
            for (var i = 0; i < this.size; i++) { // 创建雪花元素
                var left = this.getRandomThings('left'); // 获取随机的left值
                var top = this.getRandomThings('top'); // 获取随机的top值
                var snowSize = this.getRandomThings('size'); // 获取随机的雪花大小
                var snow = document.createElement("div"); // 创建雪花元素
                snow.style.cssText = 'position:absolute;color:#FFFFFF;'; // 设置元素样式
                snow.style['font-size'] = snowSize + 'px'; // 设置字体大小
                snow.style.left = left + 'px'; // 设置left值
                snow.style.top = top + 'px'; // 设置top值
                snow.innerHTML = '&#10052;'; // 设置雪花图标（Unicode编码）
                this.item.push(snow); // 添加到雪花元素数组中
                fragment.appendChild(snow); // 添加到文档片段中
            }
            this.box.appendChild(fragment); // 将文档片段添加到容器中
        };

        Snow.prototype.start = function () {
            var that = this;
            var num = 0;
            for (var i = 0; i < this.size; i++) { // 遍历雪花元素数组
                var snow = this.item[i];
                if ((i + 1) % this.downSize == 0) { // 每downSize个雪花一组，控制下落速度
                    num++;
                }
                (function (s, n) { // 使用闭包保存snow和num的值
                    setTimeout(function () { // 定时器，实现雪花分批下落
                        that.doStart(s); // 调用doStart方法使雪花开始下落
                    }, 1000 * n); // 每隔n秒下落一组雪花
                })(snow, num);
            }
        };

        // 针对每个雪花的定时处理
        Snow.prototype.doStart = function (snow) {
            var that = this;
            (function (s) {
                var increTop = that.getRandomThings('incre'); // 获取向下的速度
                var increLeft = that.getRandomThings('increLeft'); // 获取向右的速度
                var x = parseInt(getStyle(s, 'left')), y = parseInt(getStyle(s, 'top')); // 获取当前的left和top值

                if (s.timmer) return; // 如果定时器已存在，则不执行后续代码
                s.timmer = setInterval(function () { // 设置定时器，使雪花动起来
                    // 超过右边或者底部重新开始
                    if (y > (screenHeight - 5) || x > (screenWidth - 30)) {
                        // 重新回到天上开始往下
                        increTop = that.getRandomThings('incre');
                        increLeft = that.getRandomThings('increLeft');

                        // 重新随机属性
                        var left = that.getRandomThings('left');
                        var top = that.getRandomThings('top');
                        var snowSize = that.getRandomThings('size');
                        s.style.left = left + 'px';
                        s.style.top = top + 'px';
                        s.style['font-size'] = snowSize + 'px';
                        y = top;
                        x = left;
                        n = 0;

                        return;
                    }

                    // 加上系数，当随机数大于0.5时速度加快，小于0.5时速度减慢，形成飘动效果
                    x += Math.random() > 0.5 ? increLeft * 1.1 : increLeft * 0.9;
                    y += Math.random() > 0.5 ? increTop * 1.1 : increTop * 0.9;

                    // 设置left和top值使雪花动起来
                    s.style.left = x + 'px';
                    s.style.top = y + 'px';
                }, speed); // 每隔speed毫秒执行一次定时器中的代码
            })(snow);
        };

        // 获取元素的样式值
        function getStyle(obj, prop) {
            var prevComputedStyle = document.defaultView ? document.defaultView.getComputedStyle(obj, null) : obj.currentStyle;
            return prevComputedStyle[prop];
        }

        new Snow(200, 20); // 创建一个Snow对象，传入雪花数量和每批下落的雪花数量
    })();
    /*]]>*/
</script>
</body>
</html>